package com.powerbank.devicecenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.powerbank.common.dto.DeviceDTO;
import com.powerbank.common.dto.DeviceLocationRequest;
import com.powerbank.common.dto.DeviceStatusRequest;
import com.powerbank.common.event.device.DeviceStatusChangedEvent;
import com.powerbank.common.mq.EventPublisher;
import com.powerbank.common.result.PageResult;
import com.powerbank.common.result.Result;
import com.powerbank.common.utils.GeoUtils;
import com.powerbank.devicecenter.entity.Device;
import com.powerbank.devicecenter.mapper.DeviceMapper;
import com.powerbank.devicecenter.service.DeviceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 设备服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {

    private final DeviceMapper deviceMapper;
    private final EventPublisher eventPublisher;

    @Override
    public Result<DeviceDTO> getDeviceById(Long deviceId) {
        Device device = getById(deviceId);
        if (device == null) {
            return Result.error("设备不存在");
        }

        DeviceDTO deviceDTO = convertToDTO(device);
        return Result.success(deviceDTO);
    }

    @Override
    public Result<DeviceDTO> getDeviceByCode(String deviceCode) {
        Device device = deviceMapper.findByDeviceCode(deviceCode);
        if (device == null) {
            return Result.error("设备不存在");
        }

        DeviceDTO deviceDTO = convertToDTO(device);
        return Result.success(deviceDTO);
    }

    @Override
    public Result<List<DeviceDTO>> getAvailableDevices() {
        List<Device> devices = deviceMapper.findAvailableDevices();
        List<DeviceDTO> deviceDTOs = devices.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());

        return Result.success(deviceDTOs);
    }

    @Override
    public Result<List<DeviceDTO>> getNearbyDevices(BigDecimal longitude, BigDecimal latitude, Integer radius) {
        // 计算经纬度范围
        BigDecimal[] bounds = GeoUtils.calculateBounds(longitude, latitude, radius);
        
        List<Device> devices = deviceMapper.findByLocationRange(bounds[0], bounds[1], bounds[2], bounds[3]);
        
        // 过滤出指定半径内的设备并按距离排序
        List<DeviceDTO> nearbyDevices = devices.stream()
                .filter(device -> {
                    double distance = GeoUtils.calculateDistance(
                            longitude.doubleValue(), latitude.doubleValue(),
                            device.getLongitude().doubleValue(), device.getLatitude().doubleValue()
                    );
                    return distance <= radius;
                })
                .map(device -> {
                    DeviceDTO dto = convertToDTO(device);
                    // 注意：DeviceDTO中没有setDistance方法，需要添加该字段或使用其他方式处理
                    return dto;
                })
                .sorted((d1, d2) -> {
                    // 注意：DeviceDTO中没有getDistance方法，需要添加该字段或使用其他方式处理
                    return 0; // 暂时返回0，后续需要正确实现
                })
                .collect(Collectors.toList());

        return Result.success(nearbyDevices);
    }

    @Override
    public Result<PageResult<DeviceDTO>> getDevicesByStation(Long stationId, Integer page, Integer size) {
        Page<Device> pageParam = new Page<>(page, size);
        LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Device::getStationId, stationId)
               .orderByDesc(Device::getCreatedTime);

        IPage<Device> devicePage = page(pageParam, wrapper);
        List<DeviceDTO> deviceDTOs = devicePage.getRecords().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());

        PageResult<DeviceDTO> pageResult = new PageResult<>();
        pageResult.setRecords(deviceDTOs);
        pageResult.setTotal(devicePage.getTotal());
        pageResult.setSize(devicePage.getSize());
        pageResult.setCurrent(devicePage.getCurrent());
        pageResult.setPages(devicePage.getPages());

        return Result.success(pageResult);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> lockDevice(Long deviceId, String orderNo) {
        Device device = getById(deviceId);
        if (device == null) {
            return Result.error("设备不存在");
        }

        if (!"AVAILABLE".equals(device.getStatus())) {
            return Result.error("设备状态不可用");
        }

        // 更新设备状态为占用
        String oldStatus = device.getStatus();
        device.setStatus("OCCUPIED");
        updateById(device);

        // 发送状态变更事件
        DeviceStatusChangedEvent event = new DeviceStatusChangedEvent(
                device.getId(), device.getDeviceCode(), oldStatus, "OCCUPIED", "设备锁定");
        eventPublisher.publishDeviceEvent(event);

        log.info("设备锁定成功: deviceId={}, orderNo={}", deviceId, orderNo);
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> unlockDevice(Long deviceId, String orderNo) {
        Device device = getById(deviceId);
        if (device == null) {
            return Result.error("设备不存在");
        }

        // 更新设备状态为可用
        String oldStatus = device.getStatus();
        device.setStatus("AVAILABLE");
        updateById(device);

        // 发送状态变更事件
        DeviceStatusChangedEvent event = new DeviceStatusChangedEvent(
                device.getId(), device.getDeviceCode(), oldStatus, "AVAILABLE", "设备解锁");
        eventPublisher.publishDeviceEvent(event);

        log.info("设备解锁成功: deviceId={}, orderNo={}", deviceId, orderNo);
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> startDevice(Long deviceId, String orderNo) {
        Device device = getById(deviceId);
        if (device == null) {
            return Result.error("设备不存在");
        }

        if (!"OCCUPIED".equals(device.getStatus())) {
            return Result.error("设备状态不正确");
        }

        // 更新设备充电状态
        device.setChargingStatus("DISCHARGING");
        updateById(device);

        // 发送设备启动指令（通过MQTT）
        // TODO: 实现MQTT设备控制

        log.info("设备启动成功: deviceId={}, orderNo={}", deviceId, orderNo);
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> stopDevice(Long deviceId, String orderNo) {
        Device device = getById(deviceId);
        if (device == null) {
            return Result.error("设备不存在");
        }

        // 更新设备充电状态
        device.setChargingStatus("IDLE");
        updateById(device);

        // 发送设备停止指令（通过MQTT）
        // TODO: 实现MQTT设备控制

        log.info("设备停止成功: deviceId={}, orderNo={}", deviceId, orderNo);
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> updateDeviceStatus(DeviceStatusRequest request) {
        Device device = deviceMapper.findByDeviceCode(request.getDeviceCode());
        if (device == null) {
            return Result.error("设备不存在");
        }

        String oldStatus = device.getStatus();
        device.setStatus(request.getStatus());
        device.setBatteryLevel(request.getBatteryLevel());
        device.setSignalStrength(request.getSignalStrength());
        device.setOnlineStatus(request.getOnlineStatus());
        device.setFaultCode(request.getFaultCode());
        device.setFaultDescription(request.getFaultDescription());
        device.setRemark(request.getRemark());
        device.setLastHeartbeat(LocalDateTime.now());
        updateById(device);

        // 如果状态发生变化，发送事件
        if (!oldStatus.equals(request.getStatus())) {
            DeviceStatusChangedEvent event = new DeviceStatusChangedEvent(
                    device.getId(), device.getDeviceCode(), oldStatus, request.getStatus(), "状态更新");
            eventPublisher.publishDeviceEvent(event);
        }

        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> updateDeviceLocation(DeviceLocationRequest request) {
        Device device = deviceMapper.findByDeviceCode(request.getDeviceCode());
        if (device == null) {
            return Result.error("设备不存在");
        }

        // 检查位置变化是否超过阈值
        double distance = GeoUtils.calculateDistance(
                device.getLongitude().doubleValue(), device.getLatitude().doubleValue(),
                request.getLongitude().doubleValue(), request.getLatitude().doubleValue()
        );

        if (distance > 10) { // 超过10米才更新位置
            device.setLongitude(request.getLongitude());
            device.setLatitude(request.getLatitude());
            device.setAddress(request.getAddress());
            device.setProvince(request.getProvince());
            device.setCity(request.getCity());
            device.setDistrict(request.getDistrict());
            updateById(device);

            log.info("设备位置更新: deviceId={}, 移动距离={}米", device.getId(), distance);
        }

        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> handleDeviceHeartbeat(String deviceCode) {
        LocalDateTime now = LocalDateTime.now();
        int updated = deviceMapper.updateDeviceHeartbeat(deviceCode, now);
        
        if (updated == 0) {
            log.warn("处理设备心跳失败，设备不存在: deviceCode={}", deviceCode);
            return Result.error("设备不存在");
        }

        return Result.success();
    }

    @Override
    public Result<List<DeviceDTO>> getOfflineDevices() {
        LocalDateTime timeout = LocalDateTime.now().minusMinutes(3); // 3分钟无心跳认为离线
        List<Device> devices = deviceMapper.findOfflineDevices(timeout);
        List<DeviceDTO> deviceDTOs = devices.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());

        return Result.success(deviceDTOs);
    }

    @Override
    public Result<List<DeviceDTO>> getLowBatteryDevices() {
        List<Device> devices = deviceMapper.findLowBatteryDevices(20); // 电量低于20%
        List<DeviceDTO> deviceDTOs = devices.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());

        return Result.success(deviceDTOs);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> reportDeviceFault(Long deviceId, String faultDescription) {
        Device device = getById(deviceId);
        if (device == null) {
            return Result.error("设备不存在");
        }

        String oldStatus = device.getStatus();
        device.setStatus("FAULT");
        device.setRemark(faultDescription);
        updateById(device);

        // 发送故障事件
        DeviceStatusChangedEvent event = new DeviceStatusChangedEvent(
                device.getId(), device.getDeviceCode(), oldStatus, "FAULT", faultDescription);
        eventPublisher.publishDeviceEvent(event);

        log.info("设备故障报告: deviceId={}, description={}", deviceId, faultDescription);
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> completeDeviceMaintenance(Long deviceId) {
        Device device = getById(deviceId);
        if (device == null) {
            return Result.error("设备不存在");
        }

        String oldStatus = device.getStatus();
        device.setStatus("AVAILABLE");
        device.setRemark("维护完成");
        updateById(device);

        // 发送状态变更事件
        DeviceStatusChangedEvent event = new DeviceStatusChangedEvent(
                device.getId(), device.getDeviceCode(), oldStatus, "AVAILABLE", "维护完成");
        eventPublisher.publishDeviceEvent(event);

        log.info("设备维护完成: deviceId={}", deviceId);
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> batchUpdateDeviceStatus(List<Long> deviceIds, String status) {
        LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Device::getId, deviceIds);
        
        Device updateDevice = new Device();
        updateDevice.setStatus(status);
        update(updateDevice, wrapper);

        log.info("批量更新设备状态: deviceIds={}, status={}", deviceIds, status);
        return Result.success();
    }

    @Override
    public Result<Object> getDeviceStatistics() {
        Map<String, Object> statistics = new HashMap<>();
        
        // 统计各状态设备数量
        LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Device::getStatus);
        List<Device> devices = list(wrapper);
        
        Map<String, Long> statusCount = devices.stream()
                .collect(Collectors.groupingBy(Device::getStatus, Collectors.counting()));
        
        statistics.put("statusCount", statusCount);
        statistics.put("totalCount", devices.size());
        
        return Result.success(statistics);
    }

    private DeviceDTO convertToDTO(Device device) {
        DeviceDTO dto = new DeviceDTO();
        BeanUtils.copyProperties(device, dto);
        return dto;
    }
}